<template>
  <n-drawer v-model:show="showModal" :width="props.width" @update-show="handleUpdateShow">
    <n-drawer-content title="路由导航" closable>
      <n-flex vertical>
        <n-input v-model:value="routePattern" type="text" clearable placeholder="搜索" />
        <n-tree
          ref="routeRef"
          class="n-route-tree"
          block-line
          cascade
          checkable
          key-field="routeId"
          label-field="routeNm"
          :show-irrelevant-nodes="false"
          :show-line="true"
          :pattern="routePattern"
          :data="dataList"
          :expanded-keys="routeExpandedKeys"
          :checked-keys="routeCheckedKeys"
          :selected-keys="routeSelectedKeys"
          @update-checked-keys="handleRouteCheckedKeysChange"
          @update-selected-keys="handleRouteSelectedKeysChange"
          @update-expanded-keys="handleRouteExpandedKeysChange"
        />
      </n-flex>
      <template #footer>
        <n-space>
          <n-button v-if="hasPermission('bmpch:menu:route:save', '保存菜单路由')" type="info" :loading="saveBtnLoading" @click="handleSave">
            <template #icon>
              <n-icon>
                <SaveOutlined />
              </n-icon>
            </template>
            保存
          </n-button>
        </n-space>
      </template>
    </n-drawer-content>
  </n-drawer>
</template>

<script lang="ts" setup>
import { h, unref, ref, watch } from 'vue';
import { NSpace, NIcon, NButton } from 'naive-ui';
import type { TreeInst } from 'naive-ui';
import { routeQry001 } from '@yanfan/bmpch-tsapi/route';
import { menuRouteQry, menuRouteSav001 } from '@yanfan/bmpch-tsapi/menu';
import type * as BMPCH from '@yanfan/bmpch-tsapi/types';
import { BorderOutlined, CheckSquareOutlined, StopOutlined, SaveOutlined } from '@vicons/antd';
import { usePermission } from '@yanfan/common/hooks';

defineOptions({
  name: 'BmpchMenuRouteTree',
  titl: '菜单路由编辑',
});

const props = withDefaults(
  defineProps<{
    show: boolean;
    width?: number;
    menuId: string | null;
  }>(),
  {
    show: false,
    width: 502,
  },
);

const emits = defineEmits<{
  (e: 'update:show', show: boolean): void;
  (e: 'refresh'): void;
}>();

const { hasPermission } = usePermission();

const routeRef = ref<TreeInst | null>(null);
const showModal = ref(false);
const saveBtnLoading = ref(false);
const dataList = ref<BMPCH.MenuRouteQry001Output_MenuRouteDto[]>([]);

const routePattern = ref<string>('');
const routeCheckedKeys = ref<Array<string>>([]);
const routeSelectedKeys = ref<Array<string>>([]);
const routeExpandedKeys = ref<Array<string>>([]);

const navRouteId = ref<string | null>(null);

watch(
  () => unref(props).show,
  (show) => {
    showModal.value = show;
    if (showModal.value) {
      routeQry001({}).then((data) => {
        handleLeafNode(null, data.list);
        dataList.value = data.list;
        loadMenuRouteData();
      });
    } else {
      dataList.value = new Array<any>();
      routeCheckedKeys.value = new Array<any>();
    }
  },
);

function handleSave() {
  if (navRouteId.value == null) {
    window.$message.warning('请选择菜单路由');
    return;
  }
  const routeCheckedData = routeRef.value?.getCheckedData();
  const routeIndeterminateData = routeRef.value?.getIndeterminateData();
  const routeList = new Array<BMPCH.MenuRouteSav001Input.RouteDto>();
  routeCheckedData?.options.forEach((option) => {
    if (option && option.routeId != null) {
      routeList.push({
        routeId: String(option.routeId),
        halfFlg: 0,
      });
    }
  });
  routeIndeterminateData?.options.forEach((option) => {
    if (option && option.routeId != null) {
      routeList.push({
        routeId: String(option.routeId),
        halfFlg: 1,
      });
    }
  });
  saveBtnLoading.value = true;
  menuRouteSav001({ menuId: props.menuId!, routeList, navRouteId: navRouteId.value })
    .then(() => {
      handleUpdateShow(false);
      window.$message.success('保存成功');
      emits('refresh');
    })
    .finally(() => (saveBtnLoading.value = false));
}

function handleLeafNode(parent: BMPCH.MenuRouteQry001Output_MenuRouteDto | null, nodes: Array<any>) {
  nodes.map((node) => {
    node.parent = parent;
    if (node.children && node.children.length === 0) {
      node.isLeaf = true;
    } else {
      handleLeafNode(node, node.children);
    }
  });
}

function loadMenuRouteData() {
  menuRouteQry({ menuId: props.menuId }).then((data) => {
    if (data.list && data.list.length > 0) {
      const checkedKeys = new Array<string>();
      const selectedKeys = new Array<string>();
      const expandedKeys = new Array<string>();
      data.list.forEach((item) => {
        expandedKeys.push(item.routeId);
        if (item.halfFlg === 0) {
          checkedKeys.push(item.routeId);
        }
        if (item.navFlg === 1) {
          selectedKeys.push(item.routeId);
        }
      });
      routeCheckedKeys.value = checkedKeys;
      routeSelectedKeys.value = selectedKeys;
      routeExpandedKeys.value = expandedKeys;
      handleNavNode(null, dataList.value);
    }
  });
}

function handleUpdateShow(show: boolean) {
  emits('update:show', show);
}

function handleRouteCheckedKeysChange(keys: Array<string>) {
  routeCheckedKeys.value = keys;
}

function handleRouteSelectedKeysChange(keys: Array<string>) {
  navRouteId.value = null;
  routeSelectedKeys.value = keys;
  handleNavNode(null, dataList.value);
}

function handleRouteExpandedKeysChange(keys: Array<string>) {
  routeExpandedKeys.value = keys;
}

function handleNavNode(parent: BMPCH.MenuRouteQry001Output_MenuRouteDto | null, nodes: Array<any>) {
  nodes.map((node) => {
    if (routeCheckedKeys.value.includes(node.routeId)) {
      if (routeSelectedKeys.value.includes(node.routeId)) {
        node.suffix = () => h(NIcon, { size: 16, color: '#0e7a0d' }, () => h(CheckSquareOutlined));
        navRouteId.value = node.routeId;
      } else {
        node.suffix = () => h(NIcon, { size: 16, color: '#767C82' }, () => h(BorderOutlined));
      }
    } else {
      node.suffix = () => h(NIcon, { size: 16, color: '#f0a020' }, () => h(StopOutlined));
    }
    if (node.children && node.children.length > 0) {
      handleNavNode(node, node.children);
    }
  });
}
</script>

<style lang="scss" scoped></style>
